import static org.junit.Assert.*;
import org.junit.BeforeClass;
import org.junit.Test;
import net.sf.json.*;

public class DBHandlerTest {
	static DBHandler db;
	static String insertString;
	static int pid;
	static int qid;
	static int resInvId;
	static int resInvIdSplit;
	static int rewInvId;
	static int sid;
	static int equipSlot;
	static int bid;
	static int crewLocId;
	static int crewTaskId;
	
	@BeforeClass
	public static void prepare() {
		db = new DBHandler();
		insertString = "" + System.currentTimeMillis();
	}

	@Test
	public void testInsertAndGetPlayer() { // add, get, update gold, locId, xp
		JSONObject addResults = db.addPlayer(insertString, 5);
		pid = addResults.getInt("id");
		assertTrue(addResults.getInt("result") == 0);
		assertTrue(pid > 0);
		
		JSONObject get1Results = db.getPlayer(insertString).getJSONArray("details").getJSONObject(0);
		assertTrue(get1Results.getInt("id") == pid);
		assertTrue(get1Results.getInt("xp") == 0);
		assertTrue(get1Results.getInt("locId") == 5);
		assertTrue(get1Results.getInt("gold") == 0);
		
		db.updateGold(pid, 100);
		db.changePlayerLoc(pid, 9);
		db.updatePlayerXp(pid, 255);
		
		JSONObject get2Results = db.getPlayer(insertString).getJSONArray("details").getJSONObject(0);
		assertTrue(get2Results.getInt("id") == pid);
		assertTrue(get2Results.getInt("xp") == 255);
		assertTrue(get2Results.getInt("locId") == 9);
		assertTrue(get2Results.getInt("gold") == 100);
	}

	@Test
	public void testQuests() { // assign, get, complete, minutes left
		JSONObject assignResults = db.assignQuest(pid, 10, 1, 2, 0, 3, 4, 5, 6);
		qid = assignResults.getInt("id");
		assertTrue(qid > 0);
		
		JSONObject updateMin = db.updateQuestMinLeft(qid, 9);
		assertTrue(updateMin.getInt("result") == 0);
		
		JSONObject updateCont = db.updateQuestContribution(qid, 1011);
		assertTrue(updateCont.getInt("result") == 0);
		
		JSONObject getResults = db.getQuests(pid).getJSONArray("details").getJSONObject(0);
		assertTrue(getResults.getInt("minLeft") == 9);
		assertTrue(getResults.getInt("contribution") == 1011);
		assertTrue(getResults.getInt("templateId") == 1);
		assertTrue(getResults.getInt("fromId") == 2);
		assertTrue(getResults.getInt("locId") == 0);
		assertTrue(getResults.getInt("reqItemId") == 3);
		assertTrue(getResults.getInt("reqItemQty") == 4);
		assertTrue(getResults.getInt("rewItemId") == 5);
		assertTrue(getResults.getInt("rewItemQty") == 6);
		
		JSONObject addResults = db.addItem(pid, 3, 0, 8);
		resInvId = addResults.getInt("id");
		
		JSONObject endQuest = db.endQuest(qid, true, pid, resInvId, 4, 0, 5, 6);
		assertTrue(endQuest.getInt("result") == 0);
		rewInvId = endQuest.getInt("id");
		
		JSONArray getResultsArray = db.getQuests(pid).getJSONArray("details");
		assertTrue(getResultsArray.isEmpty());
		
		JSONArray invItems = db.getInventoryAt(pid, 0).getJSONArray("details");
		JSONObject rewardResult = invItems.getJSONObject(1);
		assertTrue(rewardResult.getInt("itemId") == 5 && rewardResult.getInt("qty") == 6);
		
		JSONObject getItemResult = invItems.getJSONObject(0);
		assertTrue(getItemResult.getInt("id") == resInvId);
		assertTrue(getItemResult.getInt("qty") == 4);
	}

	@Test
	public void testShipsAndEquipment() { // add, equip, get attributes, delete, change active
		JSONObject addResults = db.addShip(pid, 1, 2, 3, 4, 5, 6, 7);
		sid = addResults.getInt("id");
		assertTrue(sid > 0);
		
		equipSlot = 1;
		JSONObject equip = db.equipToShip(sid, equipSlot, 2, 3, 4, 5, 6, 7, 8);
		assertTrue(equip.getInt("result") == 0);
		JSONObject changeActive = db.changeActiveShip(pid, sid);
		assertTrue(changeActive.getInt("result") == 0);
		
		JSONObject getResult = db.getShips(pid).getJSONArray("details").getJSONObject(0);
		assertTrue(getResult.getInt("shipTypeId") == 1);
		assertTrue(getResult.getInt("capacity") == 3);
		assertTrue(getResult.getInt("defense") == 4);
		assertTrue(getResult.getInt("consRes1") == 5);
		assertTrue(getResult.getInt("consQty1") == 6);
		assertTrue(getResult.getInt("consRes2") == 7);
		assertTrue(getResult.getInt("consQty2") == 8);
		
		JSONObject getEquipResult = db.getShipEquipment(sid).getJSONArray("details").getJSONObject(0);
		assertTrue(getEquipResult.getInt("slotId") == 1);
		assertTrue(getEquipResult.getInt("itemId") == 2);
	}

	@Test
	public void testBuildings() { // construct, get, delete
		JSONObject construct = db.constructBuilding(pid, 9, 9);
		assertTrue(construct.getInt("result") == 0);
		bid = construct.getInt("id");
		assertTrue(bid > 0);
		
		JSONObject getBuildingResults = db.getBuildings(pid, 9);
		assertTrue(!getBuildingResults.getJSONArray("details").isEmpty());
	}

	@Test
	public void testInventories() { // move all, move some
		// Move all from 0 to 1
		JSONObject move1Result = db.moveItem(resInvId, 1, 4);
		assertTrue(move1Result.getInt("id") > resInvId);
		resInvId = move1Result.getInt("id"); // New ID

		JSONObject getResult = db.getInventoryAt(pid, 1).getJSONArray("details").getJSONObject(0);
		assertTrue(getResult.getInt("qty") == 4);
		
		// Move 2/4 back to 0
		JSONObject move2Result = db.moveItem(resInvId, 0, 2);
		assertTrue(move2Result.getInt("id") > resInvId);
		resInvIdSplit = move2Result.getInt("id"); // Another ID
		
		// There should be two of the item at each location.
		JSONObject get1Result = db.getInventoryAt(pid, 0).getJSONArray("details").getJSONObject(0);
		JSONObject get2Result = db.getInventoryAt(pid, 1).getJSONArray("details").getJSONObject(0);
		assertTrue(get1Result.getInt("qty") == 2);
		assertTrue(get2Result.getInt("qty") == 2);
	}

	@Test
	public void testBuyAndSell() { // update sale, [Player]ItemsForSale[At], buy
		JSONObject updateSale1 = db.updateItemSale(resInvId, 1, 99);
		JSONObject updateSale2 = db.updateItemSale(resInvIdSplit, 2, 98);
		assertTrue(updateSale1.getInt("result") == 0);
		assertTrue(updateSale2.getInt("result") == 0);
		
		JSONArray getPlayerArray = db.getPlayerItemsForSale(pid).getJSONArray("details");
		JSONObject resInvIdResult = getPlayerArray.getJSONObject(0);
		assertTrue((resInvIdResult.getInt("qty") == 1 && resInvIdResult.getInt("salePrice") == 99)
				|| (resInvIdResult.getInt("qty") == 2 && resInvIdResult.getInt("salePrice") == 98));
		
		JSONArray getPlayerAtArray = db.getPlayerItemsForSaleAt(pid, 1).getJSONArray("details");
		JSONObject resInvIdResult1 = getPlayerAtArray.getJSONObject(0);
		assertTrue(resInvIdResult1.getInt("saleQty") == 1 && resInvIdResult1.getInt("salePrice") == 99);
		
		JSONObject buyResult = db.buy(pid, resInvId, 3, 99, 1, 7);
		assertTrue(buyResult.getInt("result") == 0);
		
		JSONObject getAfterBuy = db.getPlayerItemsForSale(pid);
		assertTrue(getAfterBuy.getJSONArray("details").size() == 1
				&& getAfterBuy.getJSONArray("details").getJSONObject(0).getInt("id") == resInvIdSplit);
	}

	@Test
	public void testCrew() { // get[At], add, clear
		JSONObject addCrew = db.addCrewToShip(pid, 0, 0);
		assertTrue(addCrew.getInt("result") == 0);
		
		assertTrue(db.getCrewAt(pid, 1).getJSONArray("details").size() == 0);
		assertTrue(db.getCrew(pid).getJSONArray("details").getJSONObject(0).getInt("qty") ==
				db.getCrewAt(pid, 0).getJSONArray("details").getJSONObject(0).getInt("qty"));
		db.moveCrew(pid, 0, 0, 1, 1, 1);
		
		assertTrue(db.getCrewAt(pid, 0).getJSONArray("details").size() == 0);
		assertTrue(db.getCrewAt(pid, 1).getJSONArray("details").getJSONObject(0).getInt("qty") == 1);
	}
	
	@Test
	public void testDeleteEverything() {
		// Cleans up and tests deletes!
		db.deleteCrewGroup(pid, crewLocId, crewTaskId);
		
		JSONObject deleteBuilding = db.deleteBuilding(bid);
		assertTrue(deleteBuilding.getInt("result") == 0);
		assertTrue(db.getBuildings(pid, 9).getJSONArray("details").isEmpty());
		
		db.deleteShipEquipment(sid, equipSlot);
		
		JSONObject deleteShip = db.deleteShip(sid);
		assertTrue(deleteShip.getInt("result") == 0);
		assertTrue(db.getShips(pid).getJSONArray("details").isEmpty());

		db.deleteInventoryItem(resInvId);
		db.deleteInventoryItem(resInvIdSplit);
		db.deleteInventoryItem(rewInvId);
		
		db.deleteQuest(qid);
		
		db.deletePlayer(pid);

	}
}
